﻿//TODO:
using System;
using System.Text;
using System.Collections.Generic;

namespace Pandora.Web
{
    /// <summary>
    /// TODO:
    /// </summary>
    public class HtmlBuilder
    {
        /// <summary>
        /// TODO:
        /// </summary>
        private enum State : int
        {
            Text = 0,
            Start = 1,
            Attributes = 2
        }

        private StringBuilder _Builder = null;
        private HtmlBuilder.State _State = HtmlBuilder.State.Text;

        private Stack<string> _Tags = null;
        /// <summary>
        /// TODO:
        /// </summary>
        internal Stack<string> Tags
        {
            get
            {
                if (_Tags == null)
                {
                    _Tags = new Stack<string>();
                }

                return _Tags;
            }
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public HtmlBuilder Open(string name)
        {
            switch (_State)
            {
                case HtmlBuilder.State.Start:
                    _Builder.Append(">");
                    break;
                case HtmlBuilder.State.Attributes:
                    _Builder.Append(">");
                    break;
                case HtmlBuilder.State.Text:
                    break;
            }


            _Builder.Append("<");
            _Builder.Append(name);
            _State = HtmlBuilder.State.Start;

            this.Tags.Push(name);

            return this;
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public HtmlBuilder Text(string text)
        {
            switch (_State)
            {
                case HtmlBuilder.State.Start:
                    _Builder.Append(">");
                    break;
                case HtmlBuilder.State.Attributes:
                    _Builder.Append(">");
                    break;
            }

            _Builder.Append(text);
            _State = HtmlBuilder.State.Text;

            return this;
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="selfClose"></param>
        /// <returns></returns>
        public HtmlBuilder Close(bool selfClose = false)
        {
            string name = this.Tags.Pop();
            bool isEmpty = _State == HtmlBuilder.State.Start || _State == HtmlBuilder.State.Attributes;

            if (isEmpty)
            {
                _Builder.Append(">");
            }

            //TODO:Not all self-closed tags works properly (f.e. <div/> does not). Think about implementation.
            //     May be store the list of tags available for self-closing.
            if (selfClose && isEmpty)
            {
                _Builder.Append("/>");
            }
            else
            {
                _Builder.Append("</");
                _Builder.Append(name);
                _Builder.Append(">");
            }

            _State = HtmlBuilder.State.Text;

            return this;
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <returns></returns>
        public HtmlBuilder CloseAll()
        {
            if (_Tags != null)
            {
                while (this.Tags.Count > 0)
                {
                    this.Close();
                }
            }

            return this;
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public HtmlBuilder Attribute(string name, object value)
        {
            if (_State != HtmlBuilder.State.Start && _State != HtmlBuilder.State.Attributes)
            {
                throw new Exception("Tag required"); //TODO:
            }

            if (value != null)
            {
                _Builder.Append(" ");
                _Builder.Append(name);
                _Builder.Append("=\"");
                _Builder.Append(value.ToString());
                _Builder.Append("\"");
                _State = HtmlBuilder.State.Attributes;
            }

            return this;
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return _Builder.ToString();
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="builder"></param>
        public HtmlBuilder(StringBuilder builder)
        {
            _Builder = builder;
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="capacity"></param>
        public HtmlBuilder(int capacity)
            : this(new StringBuilder(capacity))
        {
            
        }

        /// <summary>
        /// TODO:
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static implicit operator string(HtmlBuilder builder)
        {
            return builder._Builder.ToString();
        }
    }
}
